home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
math
/
alged34.zip
/
ALGEDSRC.ZIP
/
ALGFILE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-06
|
14KB
|
525 lines
/*--------------------------------------------------------------------
Alged: Algebra Editor henckel@vnet.ibm.com
Copyright (c) 1994 John Henckel
Permission to use, copy, modify, distribute and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies.
*/
#include "alged.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The following functions relate to reading and writing data files.
*/
#define push(tt) do { tt->next = tos; tos = tt; } while(0)
#define pop(tt) do { tt=tos; \
if (!tos) printf(msg[1]); else tos=tos->next; } while(0)
#define pushr(tt) do { tt->next = r; r = tt; } while(0)
#define popr(tt) do { tt=r; \
if (!r) printf(msg[2]); else r=r->next; } while(0)
/* = f + - * / ^ V N ? ( ) , used by infix read/write */
int wpr[10] = { 0,8,2,2,4,4,6,8,8,8 };
int rpr[15] = { 0,1,2,2,4,4,6,8,8,8,1,2,2 };
/* start-paren and end-paren, these are used as pseudo tokens. */
#define SPA 10
#define EPA 11
#define CMA 12
#define coper "=()+-*/^,"
#define numer "0123456789."
static char txt[2000];
char gdriver[80] = ""; // these three lines are exported to algraph.c
int gmode,pst,psz;
double lightx=1,lighty=3,lightz=2; // light source location
static int stoe=0; // see note in writetree
/*-----------------------------------------------------------------
parse option
*/
void parse_option(FILE *f, char *b) {
int i=0; double t;
switch (*b) {
case 's': fscanf(f,"%d",&bold1); break;
case 'i': fscanf(f,"%d",&bold2); break;
case 'c': fscanf(f,"%d",&norm); break;
case 'm': fscanf(f,"%d",&mcolor); break;
case 'e': fscanf(f,"%d",&sigdig); break;
case 'd': fscanf(f,"%lg",&maxrat); break;
case 'p': fscanf(f,"%d",&maxpow); break;
case 'a': fscanf(f,"%d",&ch8); break;
case 'v': fscanf(f,"%d",&i); directvideo=(i>0); break;
case 'y': fscanf(f,"%d",&yadj); break;
case '.': fscanf(f,"%d",&point); break;
case 'l': fscanf(f,"%3s",lang); break;
case 'f': fscanf(f,"%d",&postfix); break;
case 'g': fscanf(f,"%s %d %d %d",gdriver,&gmode,&pst,&psz); break;
case 'r': fscanf(f,"%lg %lg %lg",&lightx,&lighty,&lightz);
t = hypot(lightx,hypot(lighty,lightz));
if (t < 1E-20) lighty=1;
else { lightx/=t; lighty/=t; lightz/=t; }
break;
}
}
/*-----------------------------------------------------------------
get one token from the file
if nn=1 then negative signs are treated as operators.
*/
node *gettoken(FILE *f,int nn) {
int c,i;
static char buf[80];
double t;
node *p;
do {
c = fgetc(f);
if (c==';') do { c=fgetc(f); } while (c>0 && c!=10);
if (c=='?') {
fscanf(f,"%s",buf);
parse_option(f,buf);
c=0;
}
else if (c=='"') {
i = strlen(txt);
/* txt[i]=c;
fgets(txt+i+1,sizeof txt-i-2,f); */
fgets(txt+i,sizeof txt-i-1,f);
strcat(txt,"\r"); c=0;
}
else if (c=='@') {
fscanf(f,"%s",buf);
p = newvar(buf);
p->kind = FUN;
return p;
}
else if (c<0) return NULL; /* EOF */
} while (c<=' ');
if (c=='*') return newoper(MUL);
if (c=='/') return newoper(DIV);
if (c=='^') return newoper(EXP);
if (c==')') return newoper(EPA);
if (c=='(') return newoper(SPA);
if (c=='=') return newoper(EQU);
if (c=='+') return newoper(ADD);
if (c==',') return newoper(CMA);
if (c=='-') {
if (nn) return newoper(SUB);
c = fgetc(f); /* look ahead */
ungetc(c,f);
if (strchr(numer,c)) { t=0;
fscanf(f,"%lg",&t);
return newnum(-t);
}
else {
printf(msg[34]); pause; // unary minus warning
return newnum(-1);
}
}
if (strchr(numer,c)) {
ungetc(c,f);
fscanf(f,"%lg",&t);
return newnum(t);
}
i = 0;
buf[i++] = c;
while (i<25) {
c=fgetc(f);
if (strchr(coper,c)) {
if (c=='(') {
p=newnode();
p->kind=FUN;
buf[i]=0;
strcpy(p->name,buf);
p->nump = 1;
return p;
}
ungetc(c,f); break;
}
if (c<=' ') break;
buf[i++] = c;
}
buf[i]=0;
if (!strcmp(buf,"e")) return newnum(M_E);
if (!strcmp(buf,"pi")) return newnum(M_PI);
return newvar(buf);
}
/*-----------------------------------------------------------------
load infix expression
*/
node *loadinfix(char *filename) {
FILE *f;
node *tos,*p,*r,*t;
int i,y; /* y == previous was a num or var */
f = fopen(filename,"r");
if (f==NULL) {
printf(msg[3],filename);
pause;
return NULL;
}
tos = r = NULL;
*txt = y = 0;
p = gettoken(f,y);
while (p) {
if (*txt && p->kind<=NUM) {
p->msg = malloc(strlen(txt)+1);
strcpy(p->msg,txt);
*txt = 0;
}
if (y && (rpr[p->kind]==8 || rpr[p->kind]==1)) /* NEW EXPRESSION */
while (r) { /* REDUCE ALL */
popr(t);
if (t->kind > EXP) continue;
t->nump = 2;
pop(t->rt);
pop(t->lf);
if (t->lf->msg) {
t->msg = t->lf->msg;
t->lf->msg = NULL;
}
push(t);
}
if (rpr[p->kind]==1) { /* FUNC or StartPAREN */
pushr(p);
y=0;
}
else if (rpr[p->kind]==8) { /* VAR and NUM */
push(p);
y=1;
}
else if (r && rpr[p->kind] <= rpr[r->kind] &&
p->kind != EXP) { /* REDUCE */
popr(t);
if (t->kind > EXP) continue;
t->nump = 2;
pop(t->rt);
pop(t->lf);
if (t->lf->msg) {
t->msg = t->lf->msg;
t->lf->msg = NULL;
}
push(t);
continue; /* don't get more input */
}
else if (r && r->kind==FUN && p->kind==CMA) { /* COMMA */
r->nump++;
freenode(p);
y=0;
}
else if (r && r->kind==FUN && p->kind==EPA) { /* END OF FUNCTION */
popr(t);
if (t->nump>MAXP) t->nump = MAXP;
for (i=t->nump; i--; ) pop(t->parm[i]);
if (t->lf->msg) {
t->msg = t->lf->msg;
t->lf->msg = NULL;
}
push(t);
freenode(p); /* free close paren */
y=1;
}
else if (r && r->kind==SPA && p->kind==EPA) { /* MATCH PARENS */
popr(t);
freenode(t);
freenode(p);
y=1;
}
else {
if (p->kind > EXP) {
printf(msg[4]);
pause;
}
else pushr(p); /* SHIFT */
y=0;
}
p = gettoken(f,y);
}
while (r) { /* REDUCE all remaining oper */
popr(t);
if (t->kind > EXP) continue;
t->nump = 2;
pop(t->rt);
pop(t->lf);
if (t->lf->msg) {
t->msg = t->lf->msg;
t->lf->msg = NULL;
}
push(t);
}
fclose(f);
return tos;
}
/*--------------------------------------------------------------------
load a sample expression
*/
node *load(char *filename) {
FILE *f;
static char tok[80];
node *tos,*p;
int i;
double t;
f = fopen(filename,"r");
if (f==NULL) {
printf(msg[5],filename);
pause;
return NULL;
}
tos = NULL;
*txt = 0;
while (1) {
if (1 != fscanf(f,"%24s",tok)) break;
if (tok[0]==';') {
fgets(tok,sizeof tok,f);
continue;
}
if (tok[0]=='"') {
strcat(txt,tok+1); i=strlen(txt);
fgets(txt+i,sizeof txt-i-2,f);
strcat(txt,"\r");
continue;
}
if (*tok=='?') { /* --- Options ---- */
parse_option(f,tok+1);
continue;
}
if (*tok=='*') { /* ------------------ */
p = newoper(MUL);
pop(p->rt);
pop(p->lf);
push(p);
}
else if (*tok=='=') { /* ------------------ */
p = newoper(EQU);
pop(p->rt);
pop(p->lf);
push(p);
}
else if (*tok=='+') { /* ------------------ */
p = newoper(ADD);
pop(p->rt);
pop(p->lf);
push(p);
}
else if (*tok=='-' && !tok[1]) { /* ------------------ */
p = newoper(SUB);
pop(p->rt);
pop(p->lf);
push(p);
}
else if (*tok=='/') { /* ------------------ */
p = newoper(DIV);
pop(p->rt);
pop(p->lf);
push(p);
}
else if (*tok=='^') { /* ------------------ */
p = newoper(EXP);
pop(p->rt);
pop(p->lf);
push(p);
}
else if (*tok=='@') { /* ------------------ */
pop(p);
if (p->kind != NUM) printf(msg[6],tok);
strcpy(p->name,tok+1);
p->kind = FUN;
p->nump = p->value;
if (p->nump < 0) printf(msg[7],tok);
if (p->nump >= MAXP) printf(msg[8],tok);
for (i=p->nump; i--; ) {
pop(p->parm[i]);
}
push(p);
}
else if (!strcmp(tok,"e")) {
p = newnum(M_E);
push(p);
}
else if (!strcmp(tok,"pi")) {
p = newnum(M_PI);
push(p);
}
else if (*tok<='9' && *tok>='0' || *tok=='.' || *tok=='-') {
sscanf(tok,"%lg",&t);
p = newnum(t);
push(p);
}
else { /* non-operator, non-numeric */
p = newnode();
strcpy(p->name,tok);
p->kind = VAR;
p->nump = 0;
push(p);
}
if (!tos->msg && *txt) { /* Attach txt to the tos node */
tos->msg = malloc(strlen(txt)+1);
strcpy(tos->msg,txt);
*txt = 0;
}
else if (!tos->msg && tos->nump) { /* move txt up from left child */
tos->msg = tos->parm[0]->msg;
tos->parm[0]->msg = NULL;
}
}
fclose(f);
return tos;
}
/*-----------------------------------------------------------------
loadfile
*/
void loadfile(char *fn) {
node *p; char s[160];
if (!fn || !*fn) return;
if (!strchr(fn+max(strlen(fn)-4,0),'.')) {
strcpy(s,fn); fn=s; strcat(s,".ae");
}
if (postfix) p=load(fn);
else p=loadinfix(fn);
if (firf) curf = lastnode(firf)->next = reverse(p);
else curf = firf = reverse(p);
}
/*-----------------------------------------------------------------
fprinttree
*/
void fprinttree(FILE *f,node *p) {
int i;
for (i=0; i<p->nump; ++i)
fprinttree(f,p->parm[i]);
switch (p->kind) {
case NUM: if (p->value==M_PI) fprintf(f,"pi");
else if (p->value==M_E) fprintf(f,"e");
else fprintf(f," %1.16G",p->value); break;
case EQU: fprintf(f," ="); break;
case FUN: fprintf(f," %d @%s",p->nump,p->name); break;
case ADD: fprintf(f," +"); break;
case SUB: fprintf(f," -"); break;
case MUL: fprintf(f," *"); break;
case DIV: fprintf(f," /"); break;
case EXP: fprintf(f," ^"); break;
case VAR: fprintf(f," %s",p->name); break;
default: fprintf(f," ???"); break;
}
}
/*-----------------------------------------------------------------
putmsg - put message and convert \r to "
*/
void putmsg(FILE *f,char *m) {
putc('"',f);
while (*m) {
if (*m!='\r') putc(*m,f);
else if (m[1]) putc('"',f);
++m;
}
}
/*-----------------------------------------------------------------
savefile
*/
void savefile(char *fn) {
node *p;
FILE *f;
time_t t;
f = fopen(fn,"w");
if (!f) {
printf(msg[9],fn);
pause; return;
}
time(&t);
fprintf(f,msg[10],fn,ctime(&t));
p = firf;
while (p) {
if (p->msg) putmsg(f,p->msg);
else fprintf(f,";\n");
fprinttree(f,p);
fprintf(f,"\n");
p = p->next;
}
fclose(f);
}
/*-----------------------------------------------------------------
fwritetree = f + - * / ^ V N
precedence values: 0 8 2 2 4 4 6 8 8
*/
void fwritetree(FILE *f,node *p,int pr) {
int i;
if (pr > wpr[p->kind]) fprintf(f,"(");
switch (p->kind) {
case NUM: if (p->value==M_PI) fprintf(f,"pi");
else if (p->value==M_E) fprintf(f,"e");
else if (p->value<0 && stoe) fprintf(f,"(%1.16G)",p->value);
else fprintf(f,"%1.16G",p->value); break;
case EQU:
fwritetree(f,p->lf,0);
fprintf(f," = ");
fwritetree(f,p->rt,0); break;
case FUN:
fprintf(f,"%s(",p->name);
for (i=0; i<p->nump; ++i) {
fwritetree(f,p->parm[i],0);
if (i<p->nump-1) fprintf(f,",");
}
fprintf(f,")");
break;
case ADD:
fwritetree(f,p->lf,2);
fprintf(f," + ");
fwritetree(f,p->rt,3); break;
case SUB:
fwritetree(f,p->lf,2);
fprintf(f," - ");
fwritetree(f,p->rt,3); break;
case MUL:
fwritetree(f,p->lf,4);
fprintf(f,"*");
fwritetree(f,p->rt,5); break;
case DIV:
fwritetree(f,p->lf,4);
fprintf(f,"/");
fwritetree(f,p->rt,5); break;
case EXP:
fwritetree(f,p->lf,7);
fprintf(f,"^");
fwritetree(f,p->rt,6); break;
case VAR: fprintf(f,"%s",p->name); break;
default: fprintf(f,"???"); break;
}
if (pr > wpr[p->kind]) fprintf(f,")");
stoe = 0;
}
/*-----------------------------------------------------------------
writefile this writes the file using infix notation.
I had to add the stoe flag so that when the first thing in an
expression is a negative number it will get parens around
it. Otherwise it gets treated as a minus and glued to the former
expression.
*/
void writefile(char *fn) {
node *p;
FILE *f;
time_t t;
f = fopen(fn,"w");
if (!f) {
printf(msg[9],fn);
pause; return;
}
time(&t);
fprintf(f,msg[11],fn,ctime(&t));
p = firf;
while (p) {
if (p->msg) putmsg(f,p->msg);
stoe=1; // start of expression
fwritetree(f,p,0);
fprintf(f,"\n");
p = p->next;
}
fclose(f);
}